Amazon SNSでメッセージのバッチ(一括)送信出来るようになっていたのでためしてみた
いわさです。
Amazon SNSトピックを使ってメッセージ発行を行うことでシステム間の連携を行うことが出来ますが、少し前にメッセージ発行時のバッチ処理が出来るようになっていました。
従来のメッセージ発行はpublish
サブコマンドを使っていましたが、AWS CLI v2.4.0でpublish-batch
サブコマンドが新たに実装されています。
このコマンドを使うと最大10件までのメッセージを一括送信することが出来ます。
SNSの従量課金の一部はAPIリクエスト数による料金が含まれているので、バッチ送信をうまく活用できるとその部分が最大90%コスト減になります。
本日はこちらを試してみましたので紹介したいと思います。
Publish
まずは通常の発行の流れをおさらいしたいと思います。
今回は、Amazon SQSをサブスクライブさせています。
トピックを指定してメッセージをpublish
します。
iwasa.takahito@hoge ~ % aws sns publish --topic-arn arn:aws:sns:ap-northeast-1:123456789012:20220103sns --message test { "MessageId": "291403e7-7de9-59d2-b0a0-59abe0b6bb44" }
SQSキューで受信確認をしてみます。
iwasa.takahito@hoge ~ % aws sqs receive-message --queue-url https://sqs.ap-northeast-1.amazonaws.com/123456789012/20220103sqs | jq '.Messages[].Body | fromjson' | jq -r '.Message' test
受信出来ていますね。
PublishBatch
バッチ送信を行う場合は、publish-batch
サブコマンドを使いますが、publish-batch-request-entries
パラメータにリスト形式でメッセージを最大10件指定します。
バッチ送信時の注意点としてはペイロードサイズが合計256KB以内である必要があります。publish
サブコマンドでも最大は256KBでしたが、publish-batch
だと合計で256KBが最大です。この点は注意が必要ですね。
また、サービスクォーターのMessages Published per Second
についてはメッセージ数になるので仮に10件を一括送信するAPIコール数だと3000回になります。APIコール数は削減出来ますが、メッセージ送信数が減るわけではないのでその点も注意が必要です。
標準トピック
SNSはトピックが2種類あって、標準トピックとFIFOトピックがあります。
FIFOと聞くとSQSを想像すると思いますがSNSにもあり、SQSのFIFOキューでサブスクライブする場合はSNS側もFIFOである必要があります。
一括処理での送信順序は保証されていません。後述しますが、順序を保証させたい場合はFIFOトピックを使う必要があります。
まずは標準トピックで試してみます。
iwasa.takahito@hoge ~ % aws sns publish-batch --topic-arn arn:aws:sns:ap-northeast-1:123456789012:20220103sns --publish-batch-request-entries ' [ {"Id": "1", "Message": "test1"}, {"Id": "2", "Message": "test2"}, {"Id": "3", "Message": "test3"}, {"Id": "4", "Message": "test4"}, {"Id": "5", "Message": "test5"}, {"Id": "6", "Message": "test6"}, {"Id": "7", "Message": "test7"}, {"Id": "8", "Message": "test8"}, {"Id": "9", "Message": "test9"}, {"Id": "10", "Message": "test10"} ]' { "Successful": [ { "Id": "1", "MessageId": "a3940f45-3368-5c0f-98c0-5509acc32373" }, ... { "Id": "10", "MessageId": "7457572c-a931-5516-891f-0d60369a0a6a" } ], "Failed": [] }
では受信確認してみます。
iwasa.takahito@hoge ~ % aws sqs receive-message --queue-url https://sqs.ap-northeast-1.amazonaws.com/123456789012/20220103sqs --visibility-timeout 300 | jq '.Messages[].Body | fromjson' | jq -r '.Message' test4 ... test8 ... test9 ... test3 ... test7 ... test10 ... test5 ... test1 ... test2 ... test6
順序はバラバラですが、10件送信できていますね。
ちなみに、11件以上指定した場合は、一部送信されて11件目がFailed
になるわけではなく、バッチAPIコール全体が失敗します。
iwasa.takahito@hoge ~ % aws sns publish-batch --topic-arn arn:aws:sns:ap-northeast-1:123456789012:20220103sns --publish-batch-request-entries ' [ {"Id": "1", "Message": "test1"}, {"Id": "2", "Message": "test2"}, {"Id": "3", "Message": "test3"}, {"Id": "4", "Message": "test4"}, {"Id": "5", "Message": "test5"}, {"Id": "6", "Message": "test6"}, {"Id": "7", "Message": "test7"}, {"Id": "8", "Message": "test8"}, {"Id": "9", "Message": "test9"}, {"Id": "10", "Message": "test10"}, {"Id": "11", "Message": "test11"} ]' An error occurred (TooManyEntriesInBatchRequest) when calling the PublishBatch operation: The batch request contains more entries than permissible.
FIFOトピック
次の順序を保証させたい際を想定してFIFOトピックを使ってみましょう。
ちなみに、標準トピックは様々な送信先が設定出来たと思いますが、FIFOトピックについてはSQSのみです。
先程と同じくpublish-batch
サブコマンドを使用するのですが、メッセージにMessageGroupId
を含める必要があります。
このMessageGroupID
はSQS FIFOキューにおけるメッセージグループと同じです。
また重複排除のために、MessageDeduplicationId
を指定するか、トピックの「コンテンツベースのメッセージ重複排除」を有効化するか、どちらかが必要です。(※今回は後者)
iwasa.takahito@hoge ~ % aws sns publish-batch --topic-arn arn:aws:sns:ap-northeast-1:123456789012:20220103sns.fifo --publish-batch-request-entries ' [ {"Id": "400001", "Message": "test1", "MessageGroupId": "4001"}, {"Id": "400002", "Message": "test2", "MessageGroupId": "4002"}, {"Id": "400003", "Message": "test3", "MessageGroupId": "4003"}, {"Id": "400004", "Message": "test4", "MessageGroupId": "4004"}, {"Id": "400005", "Message": "test5", "MessageGroupId": "4005"}, {"Id": "400006", "Message": "test6", "MessageGroupId": "4006"}, {"Id": "400007", "Message": "test7", "MessageGroupId": "4007"}, {"Id": "400008", "Message": "test8", "MessageGroupId": "4008"}, {"Id": "400009", "Message": "test9", "MessageGroupId": "4009"}, {"Id": "400010", "Message": "test10", "MessageGroupId": "4010"} ]' { "Successful": [ { "Id": "400001", "MessageId": "faf05727-1468-57ea-b40b-0d6bbcfea876", "SequenceNumber": "10000000000000009000" }, ... { "Id": "400010", "MessageId": "ad0a5333-f45c-5d09-8393-097f5d11e3cd", "SequenceNumber": "10000000000000010006" } ], "Failed": [] }
レスポンスを確認すると、パラメータに設定した順序でSequenceNumber
が割り当てられています。
SQSで受信確認してみます。
iwasa.takahito@hoge ~ % aws sqs receive-message --queue-url https://sqs.ap-northeast-1.amazonaws.com/123456789012/20220103sqs.fifo --max-number-of-messages 10 { "Messages": [ ... "Body": ..."test1\" "Body": ..."test2\" "Body": ..."test3\" "Body": ..."test4\" "Body": ..."test5\" "Body": ..."test6\" "Body": ..."test7\" "Body": ..."test8\" "Body": ..."test9\" "Body": ..."test10\" ... ] }
指定した順序で送信されました。
さいごに
本日は、Amazon SNSの一括送信処理を使ってみました。
メッセージをまとめたり、利用側の修正が必要になりますが、冒頭で触れたとおり、うまく活用できればAPIリクエスト数を削減出来る可能性があります。
もし、APIリクエスト数が多くてネットワークリソースやリクエスト数によるコストでお悩みの場合は利用出来るか検討してみてください。